import { Graph } from '@antv/x6';
import { Clipboard } from '@antv/x6-plugin-clipboard';
import { Export } from '@antv/x6-plugin-export';
import { History as HistoryPlugin } from '@antv/x6-plugin-history';
import { Keyboard } from '@antv/x6-plugin-keyboard';
import { MiniMap } from '@antv/x6-plugin-minimap';
import { Scroller } from '@antv/x6-plugin-scroller';
import { Selection } from '@antv/x6-plugin-selection';
import { Snapline } from '@antv/x6-plugin-snapline';
import { Transform } from '@antv/x6-plugin-transform';
import { MIN_ZOOM, MAX_ZOOM } from '../../core/constant/index.js';
import {
  LITEFLOW_ANCHOR,
  LITEFLOW_ROUTER,
  registerEvents,
  registerShortcuts,
} from '../../core/common/index.js';

const debounce = (fn, wait = 100) => {
  let timer = null;
  return (...args) => {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      timer = null;
      fn(...args);
    }, wait);
  };
};

export const createFlowGraph = (container, miniMapContainer) => {
  const flowGraph = new Graph({
    virtual: false,
    async: true,
    autoResize: true,
    container,
    onEdgeLabelRendered: ({ edge, selectors, label }) => {
      const content = selectors.foContent;
      if (!content) return;
      content.style.display = 'flex';
      content.style.alignItems = 'center';
      content.style.justifyContent = 'center';
      content.style.overflow = 'hidden';
      if (label?.attrs?.label.text === '+') {
        const showContextPad = debounce((info) => {
          flowGraph.trigger('graph:showContextPad', info);
        }, 100);
        const handleClick = (event) => {
          showContextPad({
            x: event.clientX,
            y: event.clientY,
            edge,
          });
        };
        const button = document.createElement('button');
        button.className = 'liteflow-edge-add-button';
        button.type = 'button';
        button.innerText = '+';
        button.addEventListener('click', handleClick);
        content.appendChild(button);
      } else if (label?.attrs?.label.text) {
        content.appendChild(
          document.createTextNode(`${label.attrs.label.text}`),
        );
      }
    },
    connecting: {
      snap: true,
      allowBlank: false,
      allowLoop: false,
      allowNode: false,
      allowEdge: false,
      highlight: true,
      anchor: LITEFLOW_ANCHOR,
      connectionPoint: 'bbox',
      connector: {
        name: 'rounded',
        args: {
          radius: 8,
        },
      },
      router: LITEFLOW_ROUTER,
      validateEdge: ({ edge }) => {
        return !!edge?.target?.port;
      },
      validateConnection({ sourceView, targetView, sourceMagnet, targetMagnet }) {
        if (!sourceMagnet || !targetMagnet) {
          return false;
        }
        return sourceView !== targetView;
      },
    },
    background: {
      color: '#f4f7fc',
    },
    grid: {
      visible: true,
    },
    mousewheel: {
      enabled: true,
      minScale: MIN_ZOOM,
      maxScale: MAX_ZOOM,
      modifiers: ['ctrl', 'meta'],
    },
    interacting: {
      nodeMovable: true,
      edgeLabelMovable: false,
    },
  });

  flowGraph.use(
    new Transform({
      rotating: false,
      resizing: false,
    }),
  );
  flowGraph.use(
    new Snapline({
      enabled: true,
      clean: 100,
    }),
  );
  flowGraph.use(
    new Clipboard({
      enabled: true,
      useLocalStorage: true,
    }),
  );
  flowGraph.use(
    new Keyboard({
      enabled: true,
      global: false,
    }),
  );
  flowGraph.use(
    new HistoryPlugin({
      enabled: true,
      beforeAddCommand(event, args) {
        if (args.options) {
          return args.options.ignore !== true;
        }
        return true;
      },
    }),
  );
  flowGraph.use(
    new Selection({
      enabled: true,
      rubberband: false,
      movable: true,
      multiple: true,
      strict: true,
      showNodeSelectionBox: true,
      selectNodeOnMoved: true,
      pointerEvents: 'none',
    }),
  );
  flowGraph.use(
    new Scroller({
      enabled: true,
      pageVisible: false,
      pageBreak: false,
      pannable: true,
    }),
  );
  flowGraph.use(
    new MiniMap({
      width: 150,
      height: 150,
      minScale: MIN_ZOOM,
      maxScale: MAX_ZOOM,
      scalable: false,
      container: miniMapContainer,
      graphOptions: {
        async: true,
        createCellView(cell) {
          if (cell.isEdge()) {
            return null;
          }
          return undefined;
        },
      },
    }),
  );
  flowGraph.use(new Export());
  registerEvents(flowGraph);
  registerShortcuts(flowGraph);
  return flowGraph;
};

